package com.fang.system.io.mocknetty;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description TODO
 * @date 2022/7/15 2:46 下午
 **/
public class EventLoop implements Executor {
    public String eventLoopName;
    public Selector selector;
    private BlockingDeque queue = new LinkedBlockingDeque(100);
    private AtomicInteger STAT = new AtomicInteger(1);
    int NOT_STARTED = 1;
    int STARTED = 2;
    private Thread thread = null;

    public EventLoop(String name) {
        this.eventLoopName = name;
        try {
            selector = Selector.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void execute(Runnable task) {
        try {
            queue.put(task);
            this.selector.wakeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (!isInEventLoop() && STAT.incrementAndGet() == STARTED){
            new Thread(()->{
                try {
                    thread = Thread.currentThread();
                    EventLoop.this.run();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    private boolean isInEventLoop() {
        return thread == Thread.currentThread();
    }

    public void run() throws IOException {
        System.out.println("server 执行。。。。");
        for(;;){
            int num = selector.select();
            if (num > 0){
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    Handler handler = (Handler) key.attachment();
                    if (handler instanceof  ServerAcceptor){
                        // todo
                    } else if (handler instanceof ClientReader){
                        // todo
                    }
                    handler.doRead();
                }
            }
            runTask();
        }
    }

    private void runTask() {
        System.out.println("run task");
        for (int i = 0; i < 5; i++) {
            Runnable task = null;
            try {
                task = (Runnable) queue.poll(10, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (task != null) {
                queue.remove(task);
                task.run();
            }
        }
    }
}
